package com.cwl.pulgins.handle;

import com.cwl.pulgins.domain.Column;
import com.cwl.pulgins.domain.Table;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationParameterList;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiNameValuePair;
import com.intellij.psi.PsiPrimitiveType;
import com.intellij.psi.PsiType;
import com.intellij.psi.javadoc.PsiDocComment;

import java.util.HashMap;
import java.util.Map;

/**
 * @program: pulgin
 * @description:
 * @author: ChenWenLong
 * @create: 2019-09-03 11:48
 **/
public class Class2TableConverter {

    //===========================注解名称==============================
    private static final String IS_NULL = "isNull";
    private static final String ENCODING = "encoding";
    private static final String UNSIGNED = "unsigned";
    private static final String INDEX = "index";
    private static final String COMMENT = "comment";
    private static final String TYPE = "type";
    public static final char UNDERLINE = '_';
    private static final String DEFAULT_TYPE = "VARCHAR(255)";

    private static Map<PsiPrimitiveType,String> psiPrimitiveTypeMap;
    private static Map<String,String> classTypeMap;

    static {
        psiPrimitiveTypeMap = new HashMap<PsiPrimitiveType, String>();
        psiPrimitiveTypeMap.put(PsiType.BOOLEAN, "TINYINT");
        psiPrimitiveTypeMap.put(PsiType.BYTE, "SMALLINT");
        psiPrimitiveTypeMap.put(PsiType.CHAR, "SMALLINT");
        psiPrimitiveTypeMap.put(PsiType.DOUBLE, "DOUBLE");
        psiPrimitiveTypeMap.put(PsiType.FLOAT, "FLOAT");
        psiPrimitiveTypeMap.put(PsiType.SHORT, "SMALLINT");
        psiPrimitiveTypeMap.put(PsiType.INT, "INT");
        psiPrimitiveTypeMap.put(PsiType.LONG, "BIGINT");

        classTypeMap = new HashMap<String, String>();
        classTypeMap.put("java.lang.String","VARCHAR(255)");
        classTypeMap.put("java.math.BigDecimal","DECIMAL(10,2)");
        classTypeMap.put("java.util.Date","DATETIME");
        classTypeMap.put("java.lang.Integer","TINYINT(4)");
        classTypeMap.put("java.lang.Long","BIGINT(20)");
    }

    /**
     * 功能描述:
     * 〈转换器〉
     *
     * @params : [psiClass]
     * @return : com.cwl.pulgins.domain.Table
     * @author : cwl
     * @date : 2019/9/3 14:55
     */
    public Table convert(PsiClass psiClass){
        Table table = new Table();
        String tableName = camelToUnderline(psiClass.getName());
        table.setName(tableName);
        for (PsiField psiField : psiClass.getFields()) {
            Column column = new Column();
            //静态字段不处理
            if (psiField.getModifierList().hasExplicitModifier("static")){
                continue;
            }
            PsiAnnotation[] annotations = psiField.getAnnotations();
            //如果使用了我提供的注解
            if(annotations != null){
                PsiAnnotationParameterList parameterList = annotations[0].getParameterList();
                PsiNameValuePair[] attributes = parameterList.getAttributes();
                for (PsiNameValuePair attribute : attributes) {
                    String attributeName = attribute.getAttributeName();
                    String fieldName = psiField.getName();
                    column.setName(fieldName);
                    //判断是否为空
                    if(IS_NULL.equals(attributeName)){
                        String literalValue = attribute.getLiteralValue();
                        Boolean aBoolean = Boolean.valueOf(literalValue);
                        if(!aBoolean){
                            column.setIsNull("NOT NULL DEFAULT ''");
                        }
                    }
                    //判断编码
                    if(ENCODING.equals(attributeName)){
                        String literalValue = attribute.getLiteralValue();
                        column.setEncoding(literalValue);
                    }
                    //判断是否无符号
                    if(UNSIGNED.equals(attributeName)){
                        String literalValue = attribute.getLiteralValue();
                        Boolean aBoolean = Boolean.valueOf(literalValue);
                        if(aBoolean){
                            column.setUnsigned("unsigned");
                        }
                        column.setUnsigned("");
                    }
                    //判断是否创建索引
                    if(INDEX.equals(attributeName)){
                        String literalValue = attribute.getLiteralValue();
                        Boolean aBoolean = Boolean.valueOf(literalValue);
                        if(aBoolean){
                            column.setIndex("KEY `IDX_"+fieldName.toUpperCase() +"` (`"+camelToUnderline(fieldName)+"`)");
                        }
                        column.setIndex("");
                    }
                    //判断是否有注释
                    if(COMMENT.equals(attributeName)){
                        String literalValue = attribute.getLiteralValue();
                        column.setComment(literalValue);
                    }
                    //判断数据类型
                    if(TYPE.equals(attributeName)){
                        String literalValue = attribute.getLiteralValue();
                        column.setType(literalValue);
                    }
                }
                table.getColumns().add(column);
            //如果没有使用我提供的注解
            }else{
                PsiDocComment docComment = psiField.getDocComment();
                if (docComment != null) {
                    StringBuilder commentAccum = new StringBuilder();
                    for (PsiElement psiElement : docComment.getDescriptionElements()) {
                        commentAccum.append(psiElement.getText());
                    }
                    column.setComment(commentAccum.toString().replaceAll("\\n+","").trim());
                }
                column.setName(psiField.getName());
                if (psiField.getType() instanceof PsiPrimitiveType) {
                    column.setType(psiPrimitiveTypeMap.get(psiField.getType()));
                } else if (psiField.getType() instanceof PsiClassType) {
                    column.setType(classTypeMap.get(psiField.getType().getCanonicalText()));
                }
                if (column.getType() == null) {
                    column.setType(DEFAULT_TYPE);
                }
                table.getColumns().add(column);
            }
        }
        return table;
    }
    /*CREATE TABLE `test_domain` (
`${column.name}` VARCHAR(36)  NOT NULL DEFAULT ''    COMMENT '主键ID',
`${column.name}` VARCHAR(36)  NOT NULL DEFAULT ''    COMMENT '表单id',
`${column.name}` VARCHAR(36)    COMMENT '表单版本号id',
`${column.name}` VARCHAR(36)    COMMENT '表单详情id',
`${column.name}` VARCHAR(36)  NOT NULL DEFAULT ''    COMMENT '产品id',
`${column.name}` VARCHAR(36)    COMMENT '产品封面',
`${column.name}` VARCHAR(36)    COMMENT '产品名称',
`${column.name}` VARCHAR(36)    COMMENT '规格值集',
`${column.name}` VARCHAR(36)    COMMENT '应付金额 = 产品原价 * 购买数量',
`${column.name}` VARCHAR(36)    COMMENT '是否删除 0 -否 -1 是',
PRIMARY KEY (`id`)
  ) ENGINE=InnoDB ;*/
    /**
     * 功能描述:
     * 〈设置字段属性〉
     *
     * @params : [attribute, column]
     * @return : void
     * @author : cwl
     * @date : 2019/9/4 15:49
     */
    private Column handleAttribute(PsiField psiField, PsiNameValuePair attribute, Column column) {
        String attributeName = attribute.getAttributeName();
        String fieldName = psiField.getName();
        //判断是否为空
        if(IS_NULL.equals(attributeName)){
            String literalValue = attribute.getLiteralValue();
            Boolean aBoolean = Boolean.valueOf(literalValue);
            if(aBoolean){
                column.setIsNull("DEFAULT NULL");
            }
            column.setIsNull("NOT NULL DEFAULT ''");
        }
        //判断编码
        if(ENCODING.equals(attributeName)){
            String literalValue = attribute.getLiteralValue();
            column.setEncoding(literalValue);
        }
        //判断是否无符号
        if(UNSIGNED.equals(attributeName)){
            String literalValue = attribute.getLiteralValue();
            Boolean aBoolean = Boolean.valueOf(literalValue);
            if(aBoolean){
                column.setUnsigned("unsigned");
            }
            column.setUnsigned("");
        }
        //判断是否创建索引
        if(INDEX.equals(attributeName)){
            String literalValue = attribute.getLiteralValue();
            Boolean aBoolean = Boolean.valueOf(literalValue);
            if(aBoolean){
                column.setIndex("KEY `IDX_"+fieldName.toUpperCase() +"` (`"+camelToUnderline(fieldName)+"`)");
            }
            column.setIndex("");
        }
        //判断是否有注释
        if(COMMENT.equals(attributeName)){
            String literalValue = attribute.getLiteralValue();
            column.setComment(literalValue);
        }
        //判断数据类型
        if(TYPE.equals(attributeName)){
            String literalValue = attribute.getLiteralValue();
            column.setType(literalValue);
        }
        return column;
    }
    /*CREATE TABLE `test_domain` (
            `${column.name}` ${column.type} NOT NULL ,
`false` ${column.type} NOT NULL ,
`表单版本号id` ${column.type} NOT NULL ,
`表单详情id` ${column.type} NOT NULL ,
`false` ${column.type} NOT NULL ,
`产品封面` ${column.type} NOT NULL ,
`产品名称` ${column.type} NOT NULL ,
`规格值集` ${column.type} NOT NULL ,
`应付金额 = 产品原价 * 购买数量` ${column.type} NOT NULL ,
`是否删除 0 -否 -1 是` ${column.type} NOT NULL ,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB ;*/
    /**
     * 功能描述:
     * 〈对类名进行驼峰命名转成下划线命名〉
     *
     * @params : [param]
     * @return : java.lang.String
     * @author : cwl
     * @date : 2019/9/4 15:37
     */
    public String camelToUnderline(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if(i == 0){
                sb.append(Character.toLowerCase(c));
            }
            if (Character.isUpperCase(c) && i != 0) {
                sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            }
            if(!Character.isUpperCase(c) && i != 0){
                sb.append(c);
            }

        }
        return sb.toString();
    }
}
